/**
 * BrickFrame
 * 
 * Version 1.0
 *
 * Nov 29th, 2009
 * 
 * Copyright (c) 2009 Duc Nguyen
 */
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.io.ObjectInputStream;

import javax.swing.*;
/**
 * this class initiates a CAD of a brick.
 * @author Duc Nguyen, Sophia Soohoo
 *
 */
public class BrickFrame extends JFrame {

	private static final long serialVersionUID = 1L;
	/** desktop of this CAD */
	private JDesktopPane desktop;
	/** model of this CAD */
	private BrickModel model;
	/** menu bar of this Frame */
	private JMenuBar menubar;
	/** controller for file operations */
	private FileMenuController fileMenuController;
	/** controller for opening views */
	private ViewMenuController viewMenuController;
	/** controller for modifying the brick */
	private CommandMenuController commandMenuController;
	/** the commandProcessor of this CAD */
	private CommandProcessor commandProcessor;

	/**
	 * Constructor creates a desktop and a model, and adds menu items
	 */
	public BrickFrame() {
		//Set some parameters for thie JFrame
	    setTitle("BrickCAD");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setDefaultLookAndFeelDecorated(true);
		
		//Declarations 
		
		//create the desktop 
		desktop = new JDesktopPane(); //a specialized layered pane
		//make the model
		try{
			model = new BrickModel();
		}catch(BrickException b){
			System.err.print(b.getMessage());
		}
		
		//create the command Processor
		commandProcessor = CommandProcessor.makeCommandProcessor();

		//instantiate controllers	note: instantiation must occur after model instantiation
		fileMenuController = new FileMenuController(this);
		viewMenuController = new ViewMenuController(this);
		commandMenuController = new CommandMenuController(this);
       
		//Set this JFrame's content as destop
        setContentPane(desktop);
        //Make dragging a little faster but perhaps uglier.
        desktop.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
		
        //create the menu bar
        createMenu();

	}


    /**
     * create a new window and add a view to the window
     * @param view		to add to a window
     */
    public void addView(BrickView view) {
        Window window = new Window(view);
        window.setVisible(true); //necessary as of 1.3
        
        desktop.add(window);

        try {
            window.setSelected(true);
        } catch (java.beans.PropertyVetoException e) {}

    }
    /**
     * Window takes a brick view and encapsulates it within an internal frame 
     * @author Duc Nguyen
     *
     */
    private static class Window extends JInternalFrame {
    	private static final long serialVersionUID = 1L;

    	/**
    	 * Constructor
    	 * @param view 		a concrete brick view
    	 */
    	Window(BrickView view){
    		super(view.toString(),
                  true, //resizable
                  true, //closable
                  true, //maximizable
                  true);//iconifiable
            
    		setContentPane(view);
    		pack();
    		
    		// if a data view, then set maximizable and resizable to false
            if(view.getClass().equals(DataView.class)){
            	this.maximizable = false;
            	this.resizable = false;
            	//set the window size of a data view
            	setSize(220,200);
            }
            
            //set the window size of other views
            else{
            	setSize(200,200);
            }
    	}
    	
    }
    
    /**
     * Get the model
     * @return	the model
     */
	public BrickModel getModel() {
		return model;
	}
	
	/**
	 * Set the model by changing it's attributes rather than changing the reference
	 * @param model	to set
	 */
	public void setModel(BrickModel model){
		try {
			this.model.setModel(model);
		} catch (BrickException e) {
			e.printStackTrace();
		}
	}



    /**
     * get the command processor
	 * @return the command processor
	 */
	public CommandProcessor getCommandProcessor() {
		return commandProcessor;
	}

	/**
	 * get the desktop pane
     * @return the desktop
     */
    public JDesktopPane getDesktop() {
        return desktop;
    }


    /**
     * get the menu bar
     * @return the menubar
     */
    public JMenuBar getMenubar() {
        return menubar;
    }


    /**
     * get the file menu controller
     * @return the fileMenuController
     */
    public FileMenuController getFileMenuController() {
        return fileMenuController;
    }


    /**
     * get the view menu controller
     * @return the viewMenuController
     */
    public ViewMenuController getViewMenuController() {
        return viewMenuController;
    }


    /**
     * get the command menu controller
     * @return the commandMenuController
     */
    public CommandMenuController getCommandMenuController() {
        return commandMenuController;
    }
    
	/**
	 * Closes all internal frames on the BrickFrame
	 * @author Sophia S.
	 */
	public void closeAllViews() {
	    
	    JInternalFrame[] frames = this.getDesktop().getAllFrames();
	    for (int i = 0; i < frames.length; i++) {
	        frames[i].dispose();
	    }
	    
	    //Duc: clear opened view count for all view classes
	    DataView.clearViewCount();
	    FrontView.clearViewCount();
	    SideView.clearViewCount();
	    TopView.clearViewCount();
	}
	
	/**
	 * create the menu items and add to the menubar of this BrickFrame
	 * @author Sophia S.
	 */
	private void createMenu(){
        
        /**Labels for the file menu options*/
        final String[] MENUS = {"File", "Edit", "View"};
        final String[] FILEOPS = {"New", "Open", "Save", "SaveAs", "Exit"};
        final String[] EDITOPS = {"Edit Height", "Edit Width", "Edit Length", 
                "Redo", "Undo"};
        final String[] VIEWOPS = {"Open Side View", "Open Top View", 
                "Open Front View", "Open Data View"};
        
        //menu items declarations
        JMenuItem[] fmi = new JMenuItem[5];
        JMenuItem[] emi = new JMenuItem[5];
        JMenuItem[] vmi = new JMenuItem[4];
        
        //set Mnemonics for file
        final char[] fnem = new char[] {'N', 'O', 'S', 'A', 'X'};
        final char[] enem = new char[] {'H', 'W', 'L', 'R', 'U'};
        final char[] vnem = new char[] {'S', 'T', 'F', 'D'};
        
        //set Accelerators for file
        final char[] facc = new char[] {'N', 'O', 'S', 'A', 'X'};
        final char[] eacc = new char[] {'H', 'W', 'L', 'Y', 'Z'};
        final char[] vacc = new char[] {'1', '2', '3', '4'};

        menubar = new JMenuBar();
        
        JMenu[] jmenu = new JMenu[3];
        //Set the labels for the menu bar
        for (int i = 0; i < jmenu.length; i++) {
            jmenu[i] = new JMenu(MENUS[i]);
        }
        
        //add the menu items to menus
        addMenuItems(jmenu[0], fmi, fileMenuController, FILEOPS);
        addMenuItems(jmenu[1], emi, commandMenuController, EDITOPS);
        addMenuItems(jmenu[2], vmi, viewMenuController, VIEWOPS);

        //set the accelerators
        setAccelerators(fmi, facc);
        setAccelerators(emi, eacc);
        setAccelerators(vmi, vacc);
        
        //set the mnemonics
        setMnemonics(fmi, fnem);
        setMnemonics(emi, enem);
        setMnemonics(vmi, vnem);

        
        //Add the menu items "FILE", "EDIT", and "VIEW" to the menu bar
        menubar.add(jmenu[0]);
        menubar.add(jmenu[1]);
        menubar.add(jmenu[2]);       
        
        //set for menu bar items
        jmenu[0].setMnemonic('F');
        jmenu[1].setMnemonic('E');
        jmenu[2].setMnemonic('V');
        
        //Set menubar as the Frame's menu bar.
        setJMenuBar(menubar);
	}
	
	/**
	 * Adds the menu items to the menu designated
	 * @param menu  the JMenu that needs to be populated
	 * @param items the JMenuItems which need to populate into the menu
	 * @param listener  the actionListener shared by the menu items
	 * @param labels    the Labels for each of the menu items
	 */
	private void addMenuItems(JMenu menu, JMenuItem[] items, ActionListener listener, 
	        String[] labels){
	    
        for (int i = 0; i < items.length; i++) {
            
            items[i] = new JMenuItem(labels[i]);
            items[i].addActionListener(listener);
            menu.add(items[i]);
        }
	}
	
	/**
	 * Sets the accelerators for an array if menu items
	 * @param items  the JMenuItems
	 * @param acc    the list of accelerators
	 */
	private void setAccelerators(JMenuItem[] items, char[] accelerators) {
	    
	    for (int i = 0; i < items.length; i++) {  
            items[i].setAccelerator(KeyStroke.getKeyStroke(
                    accelerators[i], ActionEvent.CTRL_MASK));
	    }
	        
	}
	
	/**
	 * Sets the mnemonic for an array if menu items
	 * @param items  the JMenuItems
	 * @param acc    the list of mnemonics
	 */
	private void setMnemonics(JMenuItem[] items, char[] mnemonics) {
	    
	    for (int i = 0; i < items.length; i++) {
            items[i].setMnemonic(mnemonics[i]);      
	    }  
	}

    /**
     * to String
     */
    public String toString(){
    	return "Brick Frame";
    }

    /**
	 * initiate the CAD
	 * @param args
	 */
	public static void main(String[] args) {
      BrickFrame frame = new BrickFrame();
      frame.setSize(750, 600);
      frame.setVisible(true);
      
   }



}